﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CalculatorArithmetic
{
    class ToPostfixExp
    {
        Dictionary<String, int> priorityMap = new Dictionary<String, int>();//用于存储操作符优先级的dictionary 
        
        public ToPostfixExp()//设置运算符对应的优先级
        {  
            priorityMap.Add("+", 0);
            priorityMap.Add("-", 0);
            priorityMap.Add("*", 1);
            priorityMap.Add("/", 1);
        }
        public int GetPriority(string op)//得到一个操作符的优先级  
        {
            return priorityMap[op];
        }
        public string GetPostfixExp(string InfixExp)
        {  
            int end=0;//用index和end来得到一个操作数
            Stack<String> operatorStack = new Stack<string>();//建立栈来辅助生成后缀表达式
            string PE = "";//最后要输出的后缀表达式

            for(int i = 0; i < InfixExp.Length; i++)//遍历表达式中所有字符
            {
                char temps = InfixExp[i];

                if((('0' < temps || temps == '0') && (temps < '9' || temps == '9')) || temps.Equals('.'))//如果读取到的是数字或者小数点，end+1
                {
                    end++;
                }

                else if(temps.Equals('('))//遇到开括号，入栈
                {
                    operatorStack.Push(Convert.ToString(temps));
                }

                else if(temps.Equals(')'))//遇到闭括号
                {
                    if(operatorStack.Count == 0)//如果栈为空则清栈退出
                    {
                        operatorStack.Clear();
                        return "输入的表达式有误";
                    }
                    else if(operatorStack.Contains("("))//此时栈中包含开括号才进行下一步操作，反则报错
                    {
                        if(end != 0)
                        {
                            String tempOperand = InfixExp.Substring(i - end, end);//得到操作数 
                            PE += tempOperand + ",";
                            end = 0;
                        }

                        while(operatorStack.Peek() != "(")//栈顶不为开括号则弹出，直到遇到开括号位置
                        {
                            PE += operatorStack.Pop() + ",";    
                        }
                        operatorStack.Pop();//遇到开括号，弹出开括号，结束遇到闭括号的操作
                    }
                    else//栈中没有开括号，清栈退出
                    {
                        operatorStack.Clear();
                        return "输入的表达式有误";
                    }
                }

                else if(temps.Equals('='))//遇到等号，弹出栈中全部内容
                {
                    if (end != 0)//判断end不为零时，即读取了数字时草进行取操作数
                    {
                        String tempOperand = InfixExp.Substring(i - end, end);//得到操作数 
                        PE += tempOperand + ",";
                        end = 0;
                    }
                    while (operatorStack.Count > 0)
                        PE += operatorStack.Pop() + ",";
                    return PE.Substring(0, PE.Length - 1);//去掉末尾的逗号，返回最后得到的后缀表达式
                }

                else
                {
                    if (end != 0)//判断end不为零时，即读取了数字时草进行取操作数
                    {
                        String tempOperand = InfixExp.Substring(i - end, end);//得到操作数 
                        PE += tempOperand + ",";
                        end = 0;
                    }
                    if ((PE != "") && (InfixExp[i-1] != '('))//判断该符号是否是操作数的符号，如果不是，则PE不为空或者上一个符号不是“（”
                    {
                        //栈非空 && 栈顶不是开括号 && 栈顶运算符的优先级不低于输入的运算符的优先级时，反复弹出栈顶元素
                        while ((operatorStack.Count > 0) && (operatorStack.Peek() != "(")
                            && ((GetPriority(Convert.ToString(temps)) < GetPriority(operatorStack.Peek())) || (GetPriority(Convert.ToString(temps)) == GetPriority(operatorStack.Peek()))))
                        {
                            PE += operatorStack.Pop() + ",";
                        }
                        operatorStack.Push(Convert.ToString(temps));//往栈里存操作符
                    }
                    else//是操作数的符号，end++
                    {
                        end++;
                    }
                }
            }
            return "未输入表达式！";//去掉末尾的逗号，返回最后得到的后缀表达式
        }
    }
}
